﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace BaseTool
{
    /// <summary>
    /// 可缩放可拖拽的图像控件
    /// </summary>
    public class ConPictureBox : PictureBox
    {
        #region 参数
        /// <summary> 缩放因子 </summary>
        private float zoomFactor = 1.0f;
        /// <summary> 缩放增量 </summary>
        private float ZoomIncrement = 0.1f;
        /// <summary> 最小缩放 </summary>
        private float MinZoom = 0.01f;
        /// <summary> 最大缩放 </summary>
        private float MaxZoom = 10.0f;

        /// <summary> 最后位置 </summary>
        private Point lastLocation;
        /// <summary> 是否拖拽 </summary>
        private bool isDragging = false;
        /// <summary> 图像位置 </summary>
        private PointF imagePosition = PointF.Empty;
        #endregion

        #region 属性
        /// <summary>
        /// 图像变量
        /// </summary>
        [BrowsableAttribute(true)]
        [EditorBrowsable(EditorBrowsableState.Always)]
        [Bindable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("自定义属性")]
        [Description("获取或设置控件显示的图像")]
        public Image ShowImage
        {
            set
            {
                showImage = value;
                imagePosition = PointF.Empty;
                ZoomReset();
                ImageCenter();
                Invalidate();
            }
            get
            {
                return showImage;
            }
        }
        /// <summary> 图像变量 </summary>
        private Image showImage;
        #endregion

        /// <summary>
        /// 构造函数
        /// </summary>
        public ConPictureBox() : base()
        {
            this.DoubleBuffered = true;
            this.BackColor = Color.LightGray;
            this.BorderStyle = BorderStyle.FixedSingle;
            this.SizeChanged += SizeChangeRefresh;
            this.MouseWheel += ImageZoom_MouseWheel;
            this.MouseDown += ImageZoom_MouseDown;
            this.MouseMove += ImageZoom_MouseMove;
            this.MouseUp += ImageZoom_MouseUp;
            this.MouseDoubleClick += ImageZoom_MouseDoubleClick;
        }
        /// <summary>
        /// 构造函数（固定）
        /// </summary>
        /// <param name="isFix"> 不可缩放拖拽 </param>
        public ConPictureBox(bool isFix) : base()
        {
            this.DoubleBuffered = true;
            this.BackColor = Color.LightGray;
            this.BorderStyle = BorderStyle.FixedSingle;
            this.SizeChanged += SizeChangeRefresh;
            if (isFix)
                return;
            this.MouseWheel += ImageZoom_MouseWheel;
            this.MouseDown += ImageZoom_MouseDown;
            this.MouseMove += ImageZoom_MouseMove;
            this.MouseUp += ImageZoom_MouseUp;
            this.MouseDoubleClick += ImageZoom_MouseDoubleClick;
        }

        #region 图像操作
        /// <summary>
        /// 图像居中:使图像在水平和垂直方向上都居中
        /// (X,Y) = ( (workWidth - ScaledWidth)/2, (workHeight - ScaledHeight)/2)
        /// </summary>
        private void ImageCenter()
        {
            if (ShowImage == null) return;
            Size scaledSize = GetScaledSize();
            imagePosition = new PointF((this.ClientSize.Width - scaledSize.Width) / 2f, (this.ClientSize.Height - scaledSize.Height) / 2f);
            Invalidate();
        }
        /// <summary>
        /// 图像缩放：基于鼠标位置的缩放
        /// </summary>
        private void Zoom(float factor)
        {
            if (ShowImage == null) return;
            //获取鼠标光标位置 转换为 工作区坐标。
            Point mousePos = this.PointToClient(MousePosition);
            Size scaledSize = GetScaledSize();
            float mouseXRelative = (mousePos.X - imagePosition.X) / scaledSize.Width;
            float mouseYRelative = (mousePos.Y - imagePosition.Y) / scaledSize.Height;

            // 新缩放因子 = 当前缩放因子 + 传入的缩放增量
            float newZoom = zoomFactor + factor;
            // 使用Math.Max和Math.Min确保缩放因子在最小(MinZoom)和最大(MaxZoom)限制之间
            newZoom = Math.Max(MinZoom, Math.Min(MaxZoom, newZoom));
            zoomFactor = newZoom;
            Size newSize = GetScaledSize();
            //调整图像位置：(X,Y) = ( (workWidth - ScaledWidth)/2, (workHeight - ScaledHeight)/2)
            imagePosition = new PointF(mousePos.X - mouseXRelative * newSize.Width, mousePos.Y - mouseYRelative * newSize.Height);
            Invalidate();
        }
        /// <summary>
        /// 还原
        /// </summary>
        public void ZoomReset()
        {
            if (showImage == null)
            {
                zoomFactor = 1.0f;
                MinZoom = 0.01f;
                MaxZoom = 10.0f;
            }
            else
            {
                zoomFactor = (float)Math.Min(1.0 * this.ClientSize.Width / ShowImage.Width, 1.0 * this.ClientSize.Height / ShowImage.Height);
                MinZoom = (float)Math.Max(30.0 / Math.Max(ShowImage.Width, 30), 30.0 / Math.Max(ShowImage.Height, 30));
                MaxZoom = (float)Math.Min(1.0 * ShowImage.Width / this.ClientSize.Width, 1.0 * ShowImage.Height / this.ClientSize.Height);
                ZoomIncrement = Math.Abs(MaxZoom - MinZoom) / 100;
            }
            ImageCenter();
        }
        /// <summary>
        ///  计算图像缩放尺寸：(newW ,newH) =（width ,height）* zoomFactor
        /// </summary>
        private Size GetScaledSize()
        {
            return new Size((int)(ShowImage.Width * zoomFactor), (int)(ShowImage.Height * zoomFactor));
        }
        /// <summary>
        /// 尺寸变化后刷新居中
        /// </summary>
        private void SizeChangeRefresh(object sender, EventArgs e)
        {
            ZoomReset();
        }
        #endregion

        #region 事件方法重写
        /// <summary>
        /// 重绘
        /// </summary>
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            if (ShowImage == null) return;
            // 计算缩放后的图像尺寸
            Size scaleSize = GetScaledSize();
            // 计算绘制位置（确保居中）
            Rectangle destRect;
            if (imagePosition == PointF.Empty)
            {
                // 初始居中显示
                int x = (this.ClientSize.Width - scaleSize.Width) / 2;
                int y = (this.ClientSize.Height - scaleSize.Height) / 2;
                destRect = new Rectangle(x, y, scaleSize.Width, scaleSize.Height);
            }
            else
            {
                // 拖拽后的位置
                destRect = new Rectangle(
                    (int)imagePosition.X,
                    (int)imagePosition.Y,
                    scaleSize.Width,
                    scaleSize.Height);
            }
            // 绘制图像
            e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            e.Graphics.DrawImage(ShowImage, destRect);
        }
        /// <summary>
        /// 重设大小
        /// </summary>
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            if (ShowImage != null)
            {
                // 如果图像比控件小，则居中显示
                Size scaledSize = GetScaledSize();
                if (scaledSize.Width <= this.ClientSize.Width && scaledSize.Height <= this.ClientSize.Height)
                    ImageCenter();
            }
        }
        #endregion

        #region 鼠标事件处理
        /// <summary>
        /// 滚轮缩放
        /// </summary>
        private void ImageZoom_MouseWheel(object sender, MouseEventArgs e)
        {
            if (e.Delta > 0)
                Zoom(ZoomIncrement);
            else if (e.Delta < 0)
                Zoom(-ZoomIncrement);
        }
        /// <summary>
        /// 按下拖拽
        /// </summary>
        private void ImageZoom_MouseDown(object sender, MouseEventArgs e)
        {
            if (ShowImage == null)
                return;
            if (e.Button != MouseButtons.Left)
                return;

            lastLocation = e.Location;
            isDragging = true;
            this.Cursor = Cursors.Hand;
        }
        /// <summary>
        /// 移动显示
        /// </summary>
        private void ImageZoom_MouseMove(object sender, MouseEventArgs e)
        {
            if (ShowImage == null)
                return;
            if (!isDragging)
                return;

            int deltaX = e.X - lastLocation.X;
            int deltaY = e.Y - lastLocation.Y;
            imagePosition.X += deltaX;
            imagePosition.Y += deltaY;
            lastLocation = e.Location;
            Invalidate();
        }
        /// <summary>
        /// 松开取消拖拽
        /// </summary>
        private void ImageZoom_MouseUp(object sender, MouseEventArgs e)
        {
            isDragging = false;
            this.Cursor = Cursors.Default;
        }
        /// <summary>
        /// 双击还原
        /// </summary>
        private void ImageZoom_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            ZoomReset();
        }
        #endregion
    }
}
